#include "stdinclude.h"
#include "core/MainLoop.h"


MainLoop::MainLoop(void) :
	FRAMES_PER_SEC(0),
	CURRENT_FRAME_TIME_MILL(0),
	CURRENT_FRAME_COUNTER(0),
	running(false), processorsChanged(false)
{
	
}


MainLoop::~MainLoop(void)
{
	removeAll();
}



int MainLoop::execute(long FPS)
{	
	_assert(FPS>0);

	FRAMES_PER_SEC = FPS;
	CURRENT_FRAME_COUNTER=0;
	
	bool runLoop= true;

	long DES_FRAME_TIME_MILL = (long) (1000.0 / FRAMES_PER_SEC);
	CURRENT_FRAME_TIME_MILL = DES_FRAME_TIME_MILL;
	long currentTick=0, lastTick=0;

	running = true;
	std::list<IProcessor* const> runningProcessors;
	processorsChanged=true;

	timer.Start();
	while(runLoop)
	{		
		if (processorsChanged)
		{
			for (MainLoopProcessorList::iterator it = activeProcessors.begin(); it!=activeProcessors.end(); ++it)
			{
				runningProcessors.push_back(it->get());
			}

			processorsChanged = false;
		}

		for (std::list<IProcessor* const>::iterator it = runningProcessors.begin(); it!=runningProcessors.end(); ++it)
		{
			bool skipNext = false;

			//RUN STEP			
			
			IProcessor* processor = (*it);						
			ProcessorResultEnum stepResult = processor->runStep(CURRENT_FRAME_TIME_MILL);

			//

			switch(stepResult)
			{
				case ProcessorResultEnum::continueloopProcessorResult:
					break;

				case ProcessorResultEnum::endloopProcessorResult:
					runLoop = false;
					break;

				case ProcessorResultEnum::skipNextStepsAndContinueloopProcessorResult:
					skipNext = true;
					break;

				case ProcessorResultEnum::skipNextStepsAndEndloopProcessorResult:
					skipNext = true;
					runLoop = false;
					break;

			}
			if (skipNext)
				continue;
		}
		
		
		if(runLoop)
		{
			CURRENT_FRAME_COUNTER++;
			lastTick = currentTick;
			currentTick = timer.GetTicks();
			CURRENT_FRAME_TIME_MILL = currentTick-lastTick;		

			long avanzo = DES_FRAME_TIME_MILL-CURRENT_FRAME_TIME_MILL;
			if( avanzo > 0 )
			{
				//TOO FAST
				OsTools::Sleep(avanzo);
				currentTick = timer.GetTicks();
				CURRENT_FRAME_TIME_MILL = currentTick-lastTick;
			}
			else
			{
				//TOO SLOW
				_dbgout("Troppo lento: %d millis (max %d)\n" ,CURRENT_FRAME_TIME_MILL, DES_FRAME_TIME_MILL);
			}
		}

	}
	running = false;
	
	return 0;
}


void MainLoop::add(IProcessor* processor)
{
	if(processor!=NULL)
	{
		processor->startup();
		this->activeProcessors.push_back(std::unique_ptr<IProcessor>(processor));
		processorsChanged= true;
	}

}


void MainLoop::remove(IProcessor* processor)
{
	if(processor!=NULL)
	{
		processor->shutdown();
		//this->activeProcessors.remove(processor);
		processorsChanged= true;
	}
}

void MainLoop::removeAll()
{	
	for(MainLoopProcessorList::iterator it = activeProcessors.begin(); it!=activeProcessors.end(); ++it)
	{
		(*it)->shutdown();
	}

	activeProcessors.clear();
}